﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Compression;
using System.IO;

namespace Home.Haushalt
{
    /// <summary>
    /// helper classes for compressing and decompressing
    /// of strings and byte-streams
    /// </summary>
    public class Compress
    {
        private const int UNZIP_BUFFER_SIZE = 32768;
        private const int UNZIPPED_BYTES = 1024;


        /// <summary>
        /// Compresses a string
        /// </summary>
        /// <param name="data">the string to compress</param>
        /// <returns>a string base64-encoded</returns>
        public static string Zip(string data)
        {
            return Convert.ToBase64String(ZipToArray(data));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string Zip(byte[] data)
        {
            return Convert.ToBase64String(ZipToArray(data));
        }

        /// <summary>
        /// Compresses a string
        /// </summary>
        /// <param name="data">the string to compress</param>
        /// <returns>a resulting stream</returns>
        public static Stream ZipToStream(string data)
        {
            return new MemoryStream(ZipToArray(data));
        }

        /// <summary>
        /// Compresses a string
        /// </summary>
        /// <param name="data">the string to compress</param>
        /// <returns>a resulting byte array</returns>
        public static byte[] ZipToArray(string data)
        {
            return ZipToArray(Encoding.UTF8.GetBytes(data));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static byte[] ZipToArray(byte[] buffer)
        {
            MemoryStream destinationStream = null;

            GZipStream zipStream = null;

            try
            {
                destinationStream = new MemoryStream();

                zipStream = new GZipStream(destinationStream, CompressionMode.Compress);

                zipStream.Write(buffer, 0, buffer.Length);

                zipStream.Flush();
                destinationStream.Flush();
                zipStream.Close();

                buffer = destinationStream.ToArray();
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                if (zipStream != null) zipStream.Close();
                if (destinationStream != null) destinationStream.Close();
            }
            return buffer;
        }

        /// <summary>
        /// decompresses a string 
        /// </summary>
        /// <param name="data">the uuencoded string to decompress</param>
        /// <returns>the decompressed string</returns>
        public static string Unzip(string data)
        {
            if (data == null) throw new ArgumentNullException();

            Byte[] byteStream = Convert.FromBase64String(data);

            return Unzip(byteStream);

        }

        /// <summary>
        /// decompresses a string 
        /// </summary>
        /// <param name="data">the uuencoded string to decompress</param>
        /// <returns>the decompressed string</returns>
        public static byte[] UnzipToArray(string data)
        {
            if (data == null) throw new ArgumentNullException();

            byte[] bytes = Convert.FromBase64String(data);
            MemoryStream byteStream = new MemoryStream(bytes);

            return UnzipToArray(byteStream);

        }

        /// <summary>
        /// decompresses an array of bytes
        /// </summary>
        /// <param name="data">the byte-array to decompress</param>
        /// <returns>the resulting decompressed string</returns>
        public static string Unzip(Byte[] data)
        {
            if (data == null) throw new ArgumentNullException();

            MemoryStream sourceStream = new MemoryStream(data);

            return Unzip(sourceStream);
        }

        /// <summary>
        /// decompresses an Stream-object
        /// </summary>
        /// <param name="sourceStream">the stream decompress</param>
        /// <returns>the resulting decompressed string</returns>
        public static string Unzip(Stream sourceStream)
        {
            byte[] buffer = UnzipToArray(sourceStream);

            return Encoding.UTF8.GetString(buffer, 0, buffer.Length);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceStream"></param>
        /// <returns></returns>
        public static byte[] UnzipToArray(Stream sourceStream)
        {
            byte[] buffer = null;
            GZipStream unzipStream = null;

            string unzippedData = string.Empty;
            try
            {
                int offset = 0;
                int totalBytes = 0;
                byte[] smallBuffer = new byte[100];

                //determine the size of decompressed buffer
                //keep the incoming stream open
                unzipStream = new GZipStream(sourceStream, CompressionMode.Decompress, true);
                while (true)
                {
                    int bytesRead = unzipStream.Read(smallBuffer, 0, 100);
                    if (bytesRead == 0)
                    {
                        break;
                    }
                    offset += bytesRead;
                    totalBytes += bytesRead;
                }
                sourceStream.Flush();
                unzipStream.Close();

                //now really decompress
                buffer = new byte[totalBytes];
                sourceStream.Position = 0;
                unzipStream = new GZipStream(sourceStream, CompressionMode.Decompress, false);
                unzipStream.Read(buffer, 0, totalBytes);


                sourceStream.Flush();

                //-----------------------------------------------------
                // Attention!
                // We need to use the same encoding in Zip and Unzip!
                //-----------------------------------------------------

            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                if (unzipStream != null) unzipStream.Close();
                if (sourceStream != null) sourceStream.Close();
            }
            return buffer;
        }
    }
}

